import java.lang.Exception
import java.util.*

/**
 * 主方法
 */
//fun Function 方法(函数),代表当前是一个方法的修饰
//main 方法名,并且是一个关键字,main代表主方法,也就是程序的入口
//args 参数名, 注意,在kotlin中,参数名和类型与java是相反的,参数名在前,类型在后
//Array<String> string类型的数组,在kotlin中是没有[]这个概念的,所有java中[]的声明,都是Array
//println 与java中system.out.println一样,是系统输出,省略了部分,是对java语法的封装
//在kotlin中是没有分号的,但是需要注意一行内,换行相当于分号
fun main(args: Array<String>): Unit {
//    println("Hello,world!!")
//    println(max(6, 5))
//    println(str)
//    a = 13
//    println(a)
//    array.add("Flutter")
//    println("hello,$name")
//    println("1+2 = ${1 + 2}")
//    println("a ${if (a >= 10) "大于等于10" else "小于10"}")

//    val person = Person("lc", false) //构造不需要使用new的关键字
//    person.name = ""//因为声明时,使用val,没有setter方法,不可以重新赋值
//    person.isMarried = true //因为声明时,使用var,有setter方法,可以进行重新赋值
//    println(person.name)
//    println(person.isMarried)

//    val rectangle = Rectangle(10, 11)
//    println(rectangle.width)
//    println(rectangle.height)
//    println(rectangle.isSquare)

//    println(getColorStr(Color.GREEN))
//    println(mix(Color.RED, Color.YELLOW))
//    play()
    println(set)
    println(list)
    println(map)
}

/**
 * 方法(函数)
 */
//: Int代表当前方法的返回值,在kotlin中,所有的方法都是有返回值,只是有的方法返回值为Unit,相当于java中的void
//如果有返回值的方法,可以转为另一种表达形式,等号的形式
//在kotlin中所有的一行代码,都可以是一个表达式
//在kotlin中,Int的声明必须是以大写字母开头
//fun max(a: Int, b: Int): Int {
//    return if (a > b) a else b
//}

fun max(a: Int, b: Int): Int = if (a > b) a else b

/**
 * 变量
 * 可变变量和不可变变量(常量)
 * val (value) 不可变变量(常量),在初始化之后不能再次赋值,对应的是Java中的final修饰符
 * var (variable) 可变变量,这种变量的值是可以被改变的,对应java的普通变量
 * 两种变量的类型是可以不写的,在kotlin中可以通过赋值的类型,来决定变量的类型
 * 当初始化时类型被固定,再次赋值时,给出的值也必须符合
 * 使用val定义一个集合时,与Java相同,集合的内容是可变的
 */

val str = "这是一个String"

val array = arrayListOf("java", "kotlin")

var a = 12

/**
 * 字符串模板
 * 在代码中声明一个name,可以在输出时使用$来进行使用,并且可以来进行一些计算和简单的逻辑,与Java中数据绑定xml里的操作类似
 */
val name = "lc"

/**
 * 类和属性
 */
class Person(
    val name: String //只读属性,生成一个字段和一个简单的getter
    , var isMarried: Boolean //可写属性,生成一个字段,一个getter,一个setter
)

//自定义访问器,如果getter和setter中需要额外的逻辑,可以通过自定义访问器实现
class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean //声明属性
        get() {
            return height == width //声明这个属性的getter方法
        }
}

/**
 * 枚举和when
 * 在枚举类中,每个逗号都代表一个枚举的类型,如果在其中需要写方法,则需要添加一个分号来分割
 */
enum class Color(val r: Int, val g: Int, val b: Int) {
    RED(255, 0, 0),
    ORANGE(255, 165, 0),
    YELLOW(255, 255, 0),
    GREEN(0, 255, 255),
    BLUE(0, 0, 255);

    fun rgb() = (r * 256 + g) * 256 + b
}

//fun getColorStr(color: Color) =
//    when (color) {
//        Color.RED -> "red"
//        Color.ORANGE -> "orange"
//        Color.YELLOW -> "yellow"
//        Color.GREEN -> "green"
//        Color.BLUE -> "blue"
//    }

fun getColorStr(color: Color) =
    when (color) {
        Color.RED, Color.ORANGE, Color.YELLOW -> "warn"
        Color.GREEN -> "neutral"
        Color.BLUE -> "cold"
    }

//list ArrayList set
fun mix(c1: Color, c2: Color) =
    when (setOf(c1, c2)) {
        setOf(Color.RED, Color.YELLOW) -> "ORANGE"
        setOf(Color.YELLOW, Color.BLUE) -> "GREEN"
        else -> throw Exception("不知道是什么颜色")
    }

//when可以不添加判断条件,可以直接在分支中进行判断
fun mixOpt(c1: Color, c2: Color) =
    when {
        (c1 == Color.RED && c2 == Color.YELLOW) || (c1 == Color.YELLOW && c2 == Color.RED)
        -> "ORANGE"
        (c1 == Color.YELLOW && c2 == Color.BLUE) || (c1 == Color.BLUE && c2 == Color.YELLOW)
        -> "GREEN"
        else -> throw Exception("不知道是什么颜色")
    }

val oneToOne = 1..10 //1-10之间的整数 并且包含10
val oneToNine = 1 until 10 //1-10之间的整数,但是不包括10


/**
 * 循环
 * 在kotlin中,while do-while 循环和Java完全一致
 */
fun fizzBuzz(i: Int) = when {
    i % 15 == 0 -> "FizzBuzz"
    i % 5 == 0 -> "Buzz"
    i % 3 == 0 -> "Fizz"
    else -> "$i"
}

//kotlin中,循环只有唯一一种存在的形式, for <item> in <elements>
fun play() {
//    for (i in 1..100) {
//        println(fizzBuzz(i))
//    }
    //step 是步伐的意思,相当于循环的间隔 downTo 倒数的意思,循环区间时默认是正数的
//    for (i in 100 downTo 1 step 20) {
//        println(fizzBuzz(i))
//    }

    val binaryReps = TreeMap<Char, String>()

    for (c in 'A'..'F') {//使用字符区间迭代A到F之间的字符
        val binary = Integer.toBinaryString(c.toInt())//把得到数ASCII码转换为二进制
        binaryReps[c] = binary//根据键值对把对应的值存入map
    }

    for ((letter, binary) in binaryReps) {//迭代MAP
        println("$letter = $binary")//循环时,letter代表map的key,binary代表map的value
    }
}

/**
 * 集合,创建集合的3种默认形式
 */
val set = setOf(1, 2, 3)
val list = listOf(1, 2, 3)
val map = mapOf(1 to "one", 2 to "two")

//fun <T> joinToString()